package com.thoughtworks.mobinium.android;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Intent;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView;

import com.thoughtworks.mobinium.parser.ScriptVisitor;

public class AndroidScriptVisitor extends TestCase implements ScriptVisitor {

	private static final String SUCCESS = "passed";
	private Instrumentation instrumentation;
	private Activity activity;
	private String packageName;
	private Map<String, String> testResults;

	public AndroidScriptVisitor(Instrumentation instrumentation) {
		this.instrumentation = instrumentation;
		this.testResults = new HashMap<String, String>();
	}

	public Map<String, String> getResults() {
		return testResults;
	}

	public void visitApplication(String appName) {
		Log.i("visitApplication", appName);
		Intent intent = new Intent(Intent.ACTION_MAIN);
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		try {
			intent.setClass(instrumentation.getTargetContext(), Class
					.forName(appName));
			packageName = appName.substring(0, appName.lastIndexOf("."));
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		activity = instrumentation.startActivitySync(intent);
	}

	public void visitAssertion(String controlName, String expectedValue) {
		Log.i("visitAssertion", controlName);
		View view = findView(controlName);
		String assertion = "assert" + " " + controlName + " " + expectedValue;
		if (view instanceof TextView) {
			try {
				assertEquals(expectedValue, ((TextView) view).getText().toString());
				testResults.put(assertion, SUCCESS);
			} catch (AssertionFailedError ex) {
				testResults.put(assertion, ex.getMessage());
			}
			return;
		}
		throw new RuntimeException("View type must be a text view");
	}

	public void visitMenu(String id) {
		//instrumentation.invokeMenuActionSync(activity, id, 0);
	}
	
	public void visitBack() {
		instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
	}
	
	public void visitChoose(String controlName, final String itemValue) {
		Log.i("visitChoose", controlName);
		View view = findView(controlName);
		if (view instanceof Spinner) {
			final Spinner spinner = (Spinner) view;
			instrumentation.runOnMainSync(new Runnable() {
				public void run() {
					spinner.setSelection(findIdForItem(spinner.getAdapter(),
							itemValue));
				}
			});
			return;
		}
		throw new RuntimeException("View type is not supported");
	}

	private int findIdForItem(SpinnerAdapter adapter, String item) {
		for (int i = 0; i < adapter.getCount(); i++) {
			if (adapter.getItem(i).equals(item)) {
				return i;
			}
		}
		return -1;
	}

	public void visitPress(String controlName) {
		Log.i("visitPress", controlName);
		final View view = findView(controlName);
		if (view instanceof Button) {
			instrumentation.runOnMainSync(new Runnable() {
				public void run() {
					((Button) view).performClick();
				}
			});
			return;
		}
		throw new RuntimeException("View type must be a button");
	}

	public void visitSelect(String controlName, String itemValue) {

	}

	public void visitType(String controlName, String text) {
		setFocusToControl(controlName);
		instrumentation.sendStringSync(text);
	}

	private void setFocusToControl(String controlName) {
		final View view = findView(controlName);
		instrumentation.runOnMainSync(new Runnable() {
			public void run() {
				view.requestFocus();
			}
		});
	}

	private View findView(String controlName) {
		View view = activity.findViewById(AndroidHelper
				.getResourceIdForControlByName(getResourceClassName(),
						controlName));
		return view;
	}

	private String getResourceClassName() {
		return packageName + ".R";
	}

	public void visitListAssertion(String controlName,
			List<String> expectedValues) {
		// TODO Auto-generated method stub
		
	}

	public void visitListEmptyAssertion(String controlName) {
		// TODO Auto-generated method stub
		
	}

}
